package org.xw.Server;

import cn.hutool.json.JSON;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.google.gson.Gson;
import jakarta.websocket.*;
import jakarta.websocket.server.ServerEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.xw.pojo.MessagePojo;
import org.xw.service.ChatService;
import org.xw.service.MessageService;
import org.xw.utils.JWTUtil;
import org.xw.utils.ResponseUtil;

import java.io.IOException;
import java.net.URI;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import jakarta.websocket.Session;

/**
 * @author websocket服务
 */
@ServerEndpoint("/ws")
@Component
public class WebSocketServer {

    //记录当前在线连接数
    public static final Map<String, Session> sessionMap = new ConcurrentHashMap<>();
    /**
     * 这里解释一下为什么要加ApplicationContext 因为spring是单例设计而websocket 是一个多实例类，每次建立连接都会有一个新的webSocket类所以@Autowired这类自动注入注解是不起效果的，所以每次需要通过上下文来获取实例
     */

    //打印日志
    private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);

    private static MessageService messageService;

    @Autowired
    private void Message(MessageService messageService){
        WebSocketServer.messageService=messageService;
    }
    private static ChatService chatService;

    @Autowired
    private void ChatService(ChatService chatService){
        WebSocketServer.chatService=chatService;
    }

    /**
     * 判断是否是合法用户。是就返回true，反之返回false
     *
     * @param session
     * @return
     */
    public static boolean openVerify(Session session) {
        // 判断是否有合法的id
        final String id = (String) session.getUserProperties().get("id");
        if (id == "" | id == null) {
            return false;
        } else {
            return true;
        }

    }

    //连接建立成功调用的方法
    @OnOpen
    public void onOpen(Session session) {
        URI requestURI = session.getRequestURI();
        String query = requestURI.getQuery();
        String[] split = query.split("=");
        String[] split1 = split[1].split(" ");
//         判断是否合法连接，如果不是，直接执行session.close()关闭连接
        DecodedJWT t = JWTUtil.getToken(split1[1]);
        Map<String, Claim> claims = t.getClaims();
        String userId = claims.get("user_id").asString();
        if (userId != null) {
            // 根据账号添加到session列表中
            sessionMap.put(userId, session);
            log.info("用户ID为={}加入连接, 当前在线人数为：{}", userId, sessionMap.size());
        } else {
            System.out.println("onOpen中无userId");
            // 非法连接，进行释放
            try {
                session.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 转发客户端发送过来的消息
     *
     * @param message String型的json包含群id，消息，文件名,或者是千问的消息包含qwid，消息
     * @param session
     */
    @OnMessage
    public void onMessage(String message, Session session) throws NoApiKeyException, InputRequiredException {

        // 显示userID
//        String userId = JWTUtil.sessionGetUserId(session);
        log.info("服务端收到来自用户ID为={}的消息:{}", message);
//        log.info("服务端收到消息:{}", message);

        // 将JSON数据转换为对象，方便操作
        JSONObject obj = JSONUtil.parseObj(message);
        System.out.println(obj.getInt("isQw"));
        System.out.println("obj:"+obj);
        Object isQW2 = obj.get("isQW");
        Integer isQw = Integer.valueOf(isQW2.toString());
        System.out.println(isQw);
        //判断是否是千问的
        if (isQw == 1) {

            //用户消息返回用户
//            sendMessage(String.valueOf(obj.getStr("userId")), obj.toString());
            //这里用户消息存数据库，并返回内容的String值
            String content = storeToQql(obj);

            //通义消息返回用户
            ResponseUtil qwMsg = chatService.qw(obj.getStr("userId"), content);

            if (qwMsg.getCode() ==1){
                send(qwMsg,obj);
            } else if (qwMsg.getCode() ==2) {
                send(qwMsg,obj);
            }


        } else if (isQw == 0) {

            //判断用户是否还在聊天列表,在就保存数据库并发信息
            if (messageService.getMember(obj.getStr("userId"), Integer.parseInt(obj.getStr("chatId"))) != null) {
                //这里做保存,并返回内容的String值
                String content = storeToQql(obj);
                URI requestURI = session.getRequestURI();
                String query = requestURI.getQuery();
                String[] split = query.split("=");
                String[] split1 = split[1].split(" ");
//         判断是否合法连接，如果不是，直接执行session.close()关闭连接
                DecodedJWT t = JWTUtil.getToken(split1[1]);
                Map<String, Claim> claims = t.getClaims();
                String userId = claims.get("user_id").asString();
                // ------这里发送给接收人
                for (Integer id : chatService.getUserIds(Integer.parseInt(obj.getStr("chatId")))) {
                    if (!id.equals(Integer.valueOf(userId)))
                    sendMessage(String.valueOf(id),message);

                }//这里可以加未读消息用户
            }
        }

    }

    /**
     * 存数据库
     * @param obj
     */
    private String storeToQql(JSONObject obj) {
        MessagePojo messagePojo =new MessagePojo();
        messagePojo.setChatId((Integer) obj.getObj("chatId", Integer.class));
        messagePojo.setUserId( Integer.valueOf(obj.get("userId", String.class)));
        Object msg = obj.get("msg");
        String s = msg.toString();
        String[] split = s.split(",");
        String[] split1 = split[0].split(":");
        //这里有bug
        System.out.println("内容："+Arrays.toString(split1));
        String[] split2 = split1[1].split("\"");
        System.out.println(split2[1]);
        String s1 = split2[1];
        messagePojo.setRecord(s1);
        messageService.store(messagePojo);
        return s1;
    }

    //拼格式并发送的方法
    private void send(ResponseUtil qwMsg,JSONObject obj){
        Object data = qwMsg.getData();
        JSON parse = JSONUtil.parse(data);
        //这里拼格式
        Map<String, Object> map = new HashMap<>();
        map.put("userId", 0);
        map.put("chatId", obj.getObj("chatId", Integer.class));
        Map<String, Object> msg = new HashMap<>();
        msg.put("content", parse.getByPath("record"));
        msg.put("type", 1);
        map.put("msg", msg);
        map.put("file", "");
        map.put("isQw", 1);
//        long timestamp = System.currentTimeMillis();
//        map.put("time",timestamp);
        sendMessage(String.valueOf(obj.getStr("userId")), new Gson().toJson(map));
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(Session session) {
        URI requestURI = session.getRequestURI();
        String query = requestURI.getQuery();
        String[] split = query.split("=");
        String[] split1 = split[1].split(" ");
//         判断是否合法连接，如果不是，直接执行session.close()关闭连接
        DecodedJWT t = JWTUtil.getToken(split1[1]);
        Map<String, Claim> claims = t.getClaims();
        String userId = claims.get("user_id").asString();
        // 判断断开的连接是否是合法的
//        String id = JWTUtil.sessionGetUserId(session);
        if (userId !=  null) {
            sessionMap.remove(userId);
            log.info("有一连接正常关闭，移除username={}的用户session, 当前在线人数为：{}", userId, sessionMap.size());
        } else {
            userId = (String) session.getUserProperties().get("unknownId");
            sessionMap.remove(userId);
            log.info("token验证不通过，移除username={}的用户session, 当前在线人数为：{}", userId, sessionMap.size());
        }
    }

    /**
     * 异常报错
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("websocket发生异常错误:");
        error.printStackTrace();
    }

    /**
     * 服务端发送消息给客户端
     */
    private void sendMessage(String userId, String message) {
        try {
            Session toSession = sessionMap.get(userId);
            if (toSession != null) {
                log.info("服务端给客户端[{}]发送消息{}", toSession.getId(), message);
                toSession.getBasicRemote().sendText(message);
            }
        } catch (Exception e) {
            log.error("服务端发送消息给客户端失败", e);
        }
    }
}